/**
 * ...
 * @author Krzysztof Rozalski
 */

package hapi.physics;
import hapi.math.Additive;
import hapi.math.Multiplicative;
import hapi.math.Vector;
import hapi.math.Vector2D;

class Velocity implements Additive<Velocity,Velocity>, implements Multiplicative<Velocity,Float> {

	var vector:Vector2D;
	var speedCache:Speed;
	public var direction(getDirection, null):Vector2D;
	public var speed(getSpeed, null):Speed;
	
	public static function zero():Velocity {
		return new Velocity(.0, new Vector2D(.0, .0));
	}
	
	public function new(mps:Float, direction:Vector2D) {
		this.vector = direction.getNormal();
		this.vector.mult(mps);
		invalidateSpeed();
	}
	
	public function reset():Void {
		this.vector.zero();
		speedCache.reset();
	}
	
	public function applyTo( position:Vector2D, time:Time ):Vector2D {
		return position.plus(positionChangeAfter(time));
	}
	
	public function positionChangeAfter(time:Time):Vector2D {
		return vector.multNew(time.seconds);
	}
	
	public function add(v:Velocity):Velocity {
		vector.plus(v.vector);
		invalidateSpeed();
		return this;
	}
	
	public function substract(v:Velocity):Velocity {
		vector.minus(v.vector);
		invalidateSpeed();
		return this;
	}
	
	public function multiplyBy(scalar:Float):Velocity {
		vector.mult(scalar);
		invalidateSpeed();
		return this;
	}
	
	public function divideBy(scalar:Float):Velocity {
		vector.div(scalar);
		invalidateSpeed();
		return this;
	}
	
	public function toString():String {
		return speed.toString();
	}
	
	public function clone():Velocity {
		return new Velocity(vector.getLength(), vector);
	}
	
	function getSpeed():Speed {
		if (speedCache == null) calculateSpeed();
		return speedCache;
	}
	
	function getDirection():Vector2D {
		return vector.getNormal();
	}
	
	inline function calculateSpeed() {
		speedCache = new Speed(vector.getLength());
	}
	
	inline function invalidateSpeed() {
		speedCache = null;
	}
}